package com.ztstkj.lzservices.extension

import java.nio.ByteBuffer


object ByteArrayExtension {
    private const val BITS_OF_BYTE = 8
    private const val POLYNOMIAL = 0xA001
    private const val INITIAL_VALUE = 0xFFFF
    private const val FF = 0xFF

    /**
     * 字节数组转为crc16校验数组
     */
    fun ByteArray.crc16(): ByteArray {
        var res = INITIAL_VALUE
        for (data in this) {
            res = res xor (data.toInt() and FF)
            for (i in 0 until BITS_OF_BYTE) {
                res = if (res and 0x0001 == 1) res shr 1 xor POLYNOMIAL else res shr 1
            }
        }
        val lowByte: Byte = (res shr 8 and FF).toByte()
        val highByte: Byte = (res and FF).toByte()
        return this.plus(highByte).plus(lowByte)
    }

    /**
     * 字节数组转为crc16校验数组
     */
    fun IntArray.crc16(): ByteArray {
        val byteArray = ByteArray(this.size + 2)
        var res = INITIAL_VALUE
        for (index in this.indices) {
            res = res xor this[index]
            byteArray[index] = this[index].toByte()
            for (i in 0 until BITS_OF_BYTE) {
                res = if (res and 0x0001 == 1) res shr 1 xor POLYNOMIAL else res shr 1
            }
        }
        val lowByte: Byte = (res shr 8 and FF).toByte()
        val highByte: Byte = (res and FF).toByte()
        byteArray[this.size] = highByte
        byteArray[this.size + 1] = lowByte
        return byteArray
    }

    /**
     * 校验crc16是否正确
     */
    fun ByteArray.crc16Verify(): Boolean {
        if (this.size < 3) throw RuntimeException("数组长度不合法")
        var res = INITIAL_VALUE
        for (index in 0..this.size - 3) {
            res = res xor (this[index].toInt() and FF)
            for (i in 0 until BITS_OF_BYTE) {
                res = if (res and 0x0001 == 1) res shr 1 xor POLYNOMIAL else res shr 1
            }
        }
        val lowByte: Byte = (res shr 8 and FF).toByte()
        //System.err.println("低位：$lowByte")
        val highByte: Byte = (res and FF).toByte()
        //System.err.println("高位：$highByte")
        return highByte == this[this.size - 2] && lowByte == this[this.size - 1]
    }

    /**
     * 获取Crc16校验码
     */
    fun ByteArray.getCrc16String(flag: Boolean = true): ByteArray {
        val len = this.size
        // 预置 1 个 16 位的寄存器为十六进制FFFF, 称此寄存器为 CRC寄存器。
        var crc = 0xFFFF
        for (i in 0 until len) {
            crc = ((crc and 0xFF00) or (crc and 0x00FF) xor (this[i].toInt() and 0xFF))
            for (j in 0 until 8) {
                // 把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位
                if ((crc and 0x0001) > 0) {
                    // 如果移出位为 1, CRC寄存器与多项式A001进行异或
                    crc = crc.shr(1)
                    crc = crc xor 0xA001
                } else {
                    // 如果移出位为 0,再次右移一位
                    crc = crc.shr(1)
                }
            }
        }
        val result = ByteArray(2)
        result[if (flag) 0 else 1] = (crc.shr(8) and 0xFF).toByte()
        result[if (flag) 1 else 0] = (crc and 0xFF).toByte()
        return result
    }

    /**
     * 转为带格式的十六进制字符串
     */
    fun ByteArray.toHexStr(splitString: String = ""): String {
        val sb = StringBuilder()
        this.forEach {
            val hex = it.toInt() and (0xFF)
            val hexStr = Integer.toHexString(hex).uppercase()
            if (hexStr.length == 1) sb.append("0").append(hexStr).append(splitString)
            else sb.append(hexStr).append(splitString)
        }
        return sb.toString().trimEnd()
    }

    fun ByteArray.sub(startIndex: Int, len: Int = 1): ByteArray {
        return this.copyOfRange(startIndex, startIndex + len)
    }

    fun ByteArray.toInt(): Int {

        return Integer.parseInt(this.toHexStr(), 16)
    }
    fun ByteArray.toLong2(): Long {
        var result = 0L
        for (i in this.lastIndex downTo 0) {
            result = result or (this[i].toLong() and 0xFF shl ((this.size - 1 - i) * 8))
        }
        return result
//        var result: Long = 0
//        for (i in this.indices) {
//            result = result or (this[i].toLong() and 0xFF shl (8 * i))
//        }
//        return result
    }


    fun ByteArray.to1SignInt(): Int {
        if (this.size != 1) throw RuntimeException("数组长度不合法")
        return this[0].toInt()
    }

    /**
     * 字节数组转为 有符号int，占两个字节
     */
    fun ByteArray.to2SignInt(): Int {
        if (this.size != 2) throw RuntimeException("数组长度不合法")
        return (this[1].toInt() shl 8) or (this[0].toInt() and 0xFF)
    }

    fun ByteArray.to4SignLong(): Long {
        if (this.size != 4) throw RuntimeException("数组长度不合法, expected size of array is 4 ")
        return ((this[3].toInt() and 0xFF) shl 24 or (this[2].toInt() and 0xFF) shl 16 or (this[1].toInt() and 0xFF) shl 8 or (this[0].toInt() and 0xFF)).toLong()
    }

    fun ByteArray.toLong(): Long {
        require(this.size <= 8) { "ByteArray size must be <= 8" }
        return ByteBuffer.wrap(this + ByteArray(8 - this.size) { 0 }).long
    }

    /**
     * 使用必须是4个字节，高低位位置调换
     */
    fun ByteArray.lowToHigh(): ByteArray {
        require(this.size == 4) { "ByteArray size must be == 4" }
        val byteArrayNew = ByteArray(4)
        byteArrayNew[0] = this[2]
        byteArrayNew[1] = this[3]
        byteArrayNew[2] = this[0]
        byteArrayNew[3] = this[1]
        return byteArrayNew
    }

    fun Long.dump(prefix: String? = "") {
        System.err.println("${prefix ?: "输出"}：$this")
    }

    fun ByteArray.dump() {
        this.forEachIndexed { index, item -> System.err.println("${index}：$item") }
    }
}